package com.example.tool;

import com.monitorjbl.xlsx.StreamingReader;
import info.debatty.java.stringsimilarity.JaroWinkler;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.*;

import java.io.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * <p>
 * ReadBigExecl 工具类，用于表格处理
 * </p>
 *
 * @author MDX
 * @since 2023/4/22 20:06
 */
public class ReadBigExecl {
    private ReadBigExecl(){}

    public static void storage(File file) throws Exception {
        String path1 = "b.xlsx";
        //获取内容
        Map<Integer, List<String>> context=new LinkedHashMap<>();
        context = context(file);
        //比较获取结果
        Map<String, String> result=new LinkedHashMap<>();
        result = compare(context);

        //存储文件
        createUserListExcel(result,file);
    }

    /**
     * 将excel读取出来
     * @param file excel文件路径
     * @return map类型的excel文件内容
     * @throws Exception
     */
    public static Map<Integer, List<String>> context(File file) throws Exception{
        Map<Integer,List<String>> mapData = new LinkedHashMap<>();
        FileInputStream in = new FileInputStream(file);
        Workbook wk = StreamingReader.builder()
                .rowCacheSize(100)  //缓存到内存中的行数，默认是10
                .bufferSize(4096)  //读取资源时，缓存到内存的字节大小，默认是1024
                .open(in);  //打开资源，必须，可以是InputStream或者是File，注意：只能打开XLSX格式的文件
        int sheetNums = wk.getNumberOfSheets();
        for(int i = 0 ; i < sheetNums;i ++){
            List<String> sheetData = new ArrayList<>();
            Sheet sheet = wk.getSheetAt(i);
            String sheetName = wk.getSheetName(i);//表名
            //遍历所有的行
            for (Row row : sheet) {
                StringBuilder sb = new StringBuilder();
                //遍历所有的列
                for (Cell cell : row) {
                    sb.append(cell.getStringCellValue());
                }
                sheetData.add(sb.toString());
            }
            mapData.put(i,sheetData);//将表名和文件内容存入map
        }
        return mapData;
    }

    /**
     * 比较表1和表2,获取比较后的内容
     * @param context 表1和表2的内容
     * @return 比较厚内容
     * @throws Exception
     */
    public static Map<String, String> compare(Map<Integer, List<String>> context) throws Exception {
        Map<String,String> mapData = new LinkedHashMap<>();
        List<String> sheet1 = context.get(0);
        List<String> sheet2 = context.get(1);
        mapData.put(sheet1.get(0),sheet2.get(0));
        sheet1.remove(0);
        sheet2.remove(0);

        for (String s : sheet1) {
            int index = findIndex(s, sheet2);
            if (index != -1) {
                mapData.put(s, sheet2.get(index));
            }
        }
        return mapData;
    }

    /**
     * 查找数据，进行数据的相似度匹配
     * @param context 查找内容
     * @param ls 数据源
     * @return 返回查找到的索引值
     */
    private static int findIndex(String context, List<String> ls) {
        JaroWinkler jaroWinkler = new JaroWinkler();
        List<Double> similarity=new ArrayList<>();

        //相似度
        for (String l : ls) {
            similarity.add(jaroWinkler.similarity(context, l));
        }
        List<Double> similarity_copy = new ArrayList<>(similarity);
        Collections.sort(similarity_copy);//进行相似度排序

        //根据相似度查找索引值
        for (int i = 0; i < similarity.size(); i++) {
            if (Objects.equals(similarity.get(i), similarity_copy.get(similarity_copy.size() - 1))) {
                return i;
            }
        }
        return -1;
    }




    /**
     * 创建excel
     * @param listresult 是需要写入excel中的数据，通过map中的k-v来将数据写入excel
     */
    private static void createUserListExcel(Map<String, String> listresult,File file) throws IOException {
        FileInputStream in = new FileInputStream(file);
        // 1.创建HSSFWorkbook，一个HSSFWorkbook对应一个Excel文件
        XSSFWorkbook wb = new XSSFWorkbook(in);
        // 2.在workbook中添加一个sheet,对应Excel文件中的sheet
        XSSFSheet sheet = wb.createSheet("结果");

        //写入内容
        AtomicInteger R= new AtomicInteger();
        listresult.forEach((K,V)->{
            XSSFRow row = sheet.createRow(R.get());
            row.createCell(0).setCellValue(K);
            row.createCell(1).setCellValue(V);
            R.getAndIncrement();
        });
        /**
         * 上面的操作已经是生成一个完整的文件了，只需要将生成的流转换成文件即可；
         * 下面的设置宽度可有可无，对整体影响不大
         */
        // 设置单元格宽度
        int curColWidth = 0;
        for (int i = 0; i < 2; i++) {
            // 列自适应宽度，对于中文半角不友好，如果列内包含中文需要对包含中文的重新设置。
            sheet.autoSizeColumn(i, true);
            // 为每一列设置一个最小值，方便中文显示
            curColWidth = sheet.getColumnWidth(i);
            if(curColWidth<2500){
                sheet.setColumnWidth(i, 2500);
            }
        }

        //写入文件
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        wb.write(fileOutputStream);
        wb.close();
        fileOutputStream.close();
    }

    //    //测试
//    public static void main(String[] args) throws Exception {
//        File file = new File("D:\\Software-cache\\IdeaProjects\\car\\excel\\车型名称映射1.xlsx");
//        long t1 = new Date().getTime();
//        Map<Integer, List<String>> context = context(file);  //获取内容
//        Map<String, String> result = compare(context);    //比较获取结果
//        //输出结果
//        for (Map.Entry<String, String> entry : result.entrySet()) {
//            String K = entry.getKey();
//            String V = entry.getValue();
//            System.out.println(K + "------->" + V);
//        }
//        long t2 = new Date().getTime();
//        System.out.println("用时："+(t2-t1)/1000 + "秒");
//
//    }
}
